home *** CD-ROM | disk | FTP | other *** search
- /*
- * SCCS: @(#)robj.c 1.2 11/2/84 14:19:59
- * Read object files.
- *
- ***********************************************************************
- * This software is copyright of
- *
- * John M Collins
- * 47 Cedarwood Drive
- * St Albans
- * Herts, AL4 0DN
- * England +44 727 57267
- *
- * and is released into the public domain on the following conditions:
- *
- * 1. No free maintenance will be guaranteed.
- * 2. Nothing may be based on this software without
- * acknowledgement, including incorporation of this
- * notice.
- *
- * Notwithstanding the above, the author welcomes correspondence and bug
- * fixes.
- ***********************************************************************
- *
- * This particular module will obviously have to be munged beyond
- * recognition for another object format.
- */
-
- #include <stdio.h>
- #include <a.out.h>
- #include <ldfcn.h>
- #include <string.h>
- #include "unc.h"
-
- void gette(), getde(), setde(), putte(), putde();
- long gettw(), getdw();
- void reallst(), lclash(), nomem(), unimpl();
- void addit();
- char *malloc();
- long lseek();
-
- int par_entry, par_round, nmods, donedrel, donebrel;
- struct commit abstab, comtab, dreltab;
- long trelpos, drelpos, brelpos;
-
- int *symord; /* convert symbol index to symbol ordinal */
-
- ef_fids mainfile;
-
- symbol lookup(), inventsymb(), getnsymb();
-
- #define RWORD 1
- #define RLONG 2
- #define DBSIZE 100
- #define STINIT 20
-
- /*
- * Read text segment. Return 0 if not ok.
- */
-
- int rtext(ldptr, outf)
- LDFILE *ldptr; /* a.out file (possibly in library) */
- ef_fid outf; /* Output file descriptor */
- {
- t_entry tstr;
- struct aouthdr unixhdr;
- struct scnhdr sect;
- register long size;
- register int i, l;
- unsigned short inbuf[DBSIZE/2];
-
- /*
- * Initialise fields in structure.
- */
-
- tstr.t_type = T_UNKNOWN;
- tstr.t_vins = 1; /* For the moment */
- tstr.t_bdest = 0;
- tstr.t_gbdest = 0;
- tstr.t_lng = 1;
- tstr.t_reloc = R_NONE;
- tstr.t_rdisp = 0;
- tstr.t_isrel = 0;
- tstr.t_amap = 0;
- tstr.t_dref = 0;
- tstr.t_relsymb = NULL;
- tstr.t_reldisp = 0;
- tstr.t_lab = NULL;
- tstr.t_lsymb = 0;
- tstr.t_refhi = 0;
- tstr.t_reflo = 0x7fffffff;
- tstr.t_match = 0;
-
- /*
- * Read a.out header.
- */
-
- if (ldohseek(ldptr) == FAILURE) { /* no optional header */
-
- outf->ef_entry = 0;
- ldshread(ldptr,1,§); /* text header */
- outf->ef_tbase = sect.s_vaddr;
- outf->ef_tsize = sect.s_size;
-
- ldshread(ldptr,2,§); /* data header */
- outf->ef_dbase = sect.s_vaddr;
- outf->ef_dsize = sect.s_size;
-
- ldshread(ldptr,3,§); /* bss header */
- outf->ef_bbase = sect.s_vaddr;
- outf->ef_bsize = sect.s_size;
- outf->ef_end = sect.s_vaddr + sect.s_size;
- } else {
- FREAD((char *)&unixhdr,sizeof(struct aouthdr),1,ldptr);
-
- if ( N_BADMAG(unixhdr) )
- return 0;
-
- outf->ef_entry = unixhdr.entry;
- outf->ef_tbase = unixhdr.text_start;
- outf->ef_dbase = unixhdr.data_start;
- outf->ef_bbase = outf->ef_dbase + unixhdr.dsize;
- outf->ef_end = outf->ef_bbase + unixhdr.bsize;
-
- outf->ef_tsize = unixhdr.tsize;
- outf->ef_dsize = unixhdr.dsize;
- outf->ef_bsize = unixhdr.bsize;
- }
-
- ldsseek(ldptr,1); /* seek to text section */
-
- size = outf->ef_tsize;
-
- while (size > 1) {
- l = size > DBSIZE? DBSIZE: size;
- if (FREAD((char *)inbuf,1,l,ldptr) != l)
- return 0;
- l /= 2;
- for (i = 0; i < l; i++) {
- tstr.t_contents = inbuf[i];
- (void) write(outf->ef_t, (char *)&tstr, sizeof(tstr));
- }
- size -= l + l;
- }
-
- /*
- * Extra one to cope with "etext".
- */
-
- (void) write(outf->ef_t, (char *)&tstr, sizeof(tstr));
- return 1;
- }
- /*
- * Same sort of thing for the data segment.
- */
-
- int rdata(ldptr, outf)
- LDFILE *ldptr; /* a.out file (possibly in library) */
- ef_fid outf; /* Output file descriptor */
- {
- d_entry dstr;
- register long size;
- register int i, l;
- unsigned char inbuf[DBSIZE];
-
- /*
- * Initialise fields in structure.
- */
-
- dstr.d_type = D_BYTE;
- dstr.d_reloc = R_NONE;
- dstr.d_lng = 1;
- dstr.d_relsymb = NULL;
- dstr.d_reldisp = 0;
- dstr.d_lab = NULL;
-
- ldsseek(ldptr,2); /* seek to data section */
-
- size = outf->ef_dsize;
-
- while (size > 0) {
- l = size > DBSIZE? DBSIZE: size;
- if (FREAD((char *)inbuf,1,l,ldptr) != l)
- return 0;
- for (i = 0; i < l; i++) {
- dstr.d_contents = inbuf[i];
- (void) write(outf->ef_d, (char *)&dstr, sizeof(dstr));
- }
- size -= l;
- }
-
- /*
- * Repeat for BSS segment.
- */
-
- dstr.d_contents = 0;
- for (size = outf->ef_bsize; size > 0; size--)
- (void) write(outf->ef_d, (char *)&dstr, sizeof(dstr));
-
- /*
- * Extra one to cope with "end".
- */
-
- (void) write(outf->ef_d, (char *)&dstr, sizeof(dstr));
- return 1;
- }
-
- /*
- * Process symbol table segment.
- */
-
- int rsymb(ldptr, dproc, outf)
- LDFILE *ldptr; /* a.out file (possibly in library) */
- symbol (*dproc)();
- register ef_fid outf; /* Output file descriptor */
- {
- #define SYMLENGTH 256
- register symbol csym;
- struct syment isym;
- register int nsyms,symindex;
- unsigned long stroff;
- char inbuf[SYMLENGTH+1], *cp;
- int ord;
-
- nsyms = HEADER(ldptr).f_nsyms;
- stroff = HEADER(ldptr).f_symptr + nsyms*sizeof(struct syment);
-
- if (nsyms <= 0)
- nsyms = STINIT;
-
- outf->ef_stvec = (symbol *) malloc(nsyms * sizeof(symbol));
- symord = (int *) malloc(nsyms * sizeof(int));
- if (outf->ef_stvec == NULL)
- nomem();
-
- outf->ef_stcnt = 0;
- outf->ef_stmax = nsyms;
- ord = 0;
-
- for (symindex=0; symindex<nsyms; symindex++) {
- ldtbread(ldptr,symindex,&isym);
- if (isym.n_zeroes == 0) { /* get from string table */
- FSEEK(ldptr,stroff + isym.n_offset,0);
- cp = inbuf;
- do {
- if (FREAD(cp,1,1,ldptr) != 1)/* Read symbol chars 1-by-1 */
- return 0;
- if ( cp - inbuf >= SYMLENGTH )/* Check against buffer overflow */
- return 0;
- } while (*cp++ != '\0');/* Terminate on null byte */
- } else { /* get from symbol field */
- strncpy(inbuf,isym.n_name,8);
- inbuf[8] = '\0';
- }
- csym = (*dproc)(lookup(inbuf), convtosun(&isym),
- isym.n_value, outf);
- if (outf->ef_stcnt >= outf->ef_stmax)
- reallst(outf);
- outf->ef_stvec[outf->ef_stcnt++] = csym;
- symord[symindex] = ord++; /* record ordinal */
- symindex += isym.n_numaux; /* skip aux entries */
- }
- return 1;
- }
-
- /*
- * Process relocation stuff. -1 error, 0 no relocation, 1 relocation.
- */
-
- int rrel(ldptr, ldptr2, outf)
- LDFILE *ldptr,*ldptr2; /* a.out file (possibly in library) */
- ef_fid outf; /* Output file descriptor */
- {
- struct reloc crel;
- struct scnhdr tsect,dsect;
- struct syment isym;
- t_entry tstr;
- d_entry dstr;
- register int nreloc;
- long cont, pos;
-
- ldshread(ldptr,1,&tsect);
- ldshread(ldptr,2,&dsect);
- if (tsect.s_nreloc <= 0 && dsect.s_nreloc <= 0)
- return 0;
-
- nreloc = tsect.s_nreloc;
-
- ldrseek(ldptr,1);
- while (nreloc-- > 0) {
- if (FREAD((char *)&crel, sizeof(crel),1,ldptr) != 1)
- return -1;
-
- pos = crel.r_vaddr;
- gette(outf, pos, &tstr);
- if (crel.r_type == R_ABS)
- tstr.t_reloc = R_NONE;
- else
- tstr.t_reloc = R_LONG; /* what about PC-relative? */
- ldtbread(ldptr2,crel.r_symndx,&isym);
- if (isym.n_sclass == C_EXT) {
- tstr.t_relsymb = outf->ef_stvec[symord[crel.r_symndx]];
- tstr.t_reldisp = gettw(outf, pos, (int)tstr.t_reloc);
- }
- else {
- cont = gettw(outf, pos, (int)tstr.t_reloc);
- tstr.t_relsymb = getnsymb(outf, convtosun(&isym), cont);
- }
- tstr.t_relsymb->s_used++;
- putte(outf, pos, &tstr);
- }
-
- /*
- * And now repeat all that for data relocations.
- */
-
- nreloc = dsect.s_nreloc;
-
- ldrseek(ldptr,2);
- while (nreloc-- > 0) {
- if (FREAD((char *)&crel, sizeof(crel),1,ldptr) != 1)
- return -1;
-
- pos = crel.r_vaddr;
- getde(outf, pos, &dstr);
- if (crel.r_type == R_ABS)
- dstr.d_reloc = R_NONE;
- else
- dstr.d_reloc = R_LONG; /* what about PC-relative? */
-
- ldtbread(ldptr2,crel.r_symndx,&isym);
- if (isym.n_sclass == C_EXT) {
- dstr.d_relsymb = outf->ef_stvec[symord[crel.r_symndx]];
- dstr.d_reldisp = getdw(outf, pos, (int)dstr.d_reloc);
- }
- else {
- cont = getdw(outf, pos, (int)dstr.d_reloc);
- dstr.d_relsymb = getnsymb(outf, convtosun(&isym), cont);
- if (dstr.d_relsymb->s_type == S_TEXT) {
- gette(outf, cont, &tstr);
- tstr.t_dref = 1;
- putte(outf, cont, &tstr);
- }
- }
- switch (dstr.d_reloc) {
- default:
- unimpl("Data byte relocation");
- break;
- case R_WORD:
- unimpl("data word reloc");
- dstr.d_type = D_WORD;
- dstr.d_lng = 2;
- setde(outf, pos+1, D_CONT, 1);
- break;
- case R_LONG:
- dstr.d_type = D_ADDR;
- dstr.d_lng = 4;
- setde(outf, pos+1, D_CONT, 1);
- setde(outf, pos+2, D_CONT, 1);
- setde(outf, pos+3, D_CONT, 1);
- break;
- }
- dstr.d_relsymb->s_used++;
- putde(outf, pos, &dstr);
- }
- return 1;
- }
-
- /*
- * Process a symbol.
- */
-
- symbol dosymb(sy, type, val, fid)
- register symbol sy;
- int type;
- long val;
- ef_fid fid;
- {
- t_entry tstr;
- d_entry dstr;
-
- if (!sy->s_newsym) {
- if (type & S_EXT) {
- (void) fprintf(stderr, "Duplicate symbol %s\n", sy->s_name);
- /* exit(10); temporary? */
- }
- if (++sy->s_defs > nmods)
- nmods = sy->s_defs;
- sy = inventsymb("DUP");
- }
-
- sy->s_value = val;
-
- switch (type) {
- default:
- return NULL;
-
- case S_EXT|S_UNDF:
- if (val != 0) {
- sy->s_type = S_COMM;
- addit(&comtab, sy);
- }
- else
- sy->s_type = S_UNDF;
- sy->s_glob = 1;
- break;
-
- case S_EXT|S_ABS:
- sy->s_type = S_ABS;
- sy->s_glob = 1;
- addit(&abstab, sy);
- break;
-
- case S_ABS:
- sy->s_type = S_ABS;
- addit(&abstab, sy);
- break;
-
- case S_EXT|S_TEXT:
- case S_TEXT:
- sy->s_type = S_TEXT;
- gette(fid, val, &tstr);
- tstr.t_bdest = 1;
- if (type & S_EXT) {
- tstr.t_gbdest = 1;
- sy->s_glob = 1;
- }
- sy->s_link = tstr.t_lab;
- tstr.t_lab = sy;
- putte(fid, val, &tstr);
- break;
-
- case S_BSS:
- case S_EXT|S_BSS:
- sy->s_type = S_BSS;
- goto datrest;
- case S_DATA:
- case S_EXT|S_DATA:
- sy->s_type = S_DATA;
- datrest:
- getde(fid, val, &dstr);
- if (type & S_EXT)
- sy->s_glob = 1;
- sy->s_link = dstr.d_lab;
- dstr.d_lab = sy;
- putde(fid, val, &dstr);
- break;
- }
-
- sy->s_newsym = 0;
- return sy;
- }
-
-
- /*
- * Process relocation stuff in putative library modules.
- * The main function of all this is to mark which bits of the text
- * not to look at as I compare the stuff.
- *
- * As with "rrel", return -1 error, 0 no relocation, 1 relocation.
- */
-
- int rrell1(ldptr, outf)
- LDFILE *ldptr; /* a.out file (possibly in library) */
- ef_fid outf; /* Output file descriptor */
- {
- struct reloc crel;
- struct scnhdr tsect,dsect;
- t_entry tstr;
- register int nreloc;
- long pos;
-
- ldshread(ldptr,1,&tsect);
- ldshread(ldptr,2,&dsect);
- if (tsect.s_nreloc <= 0 && dsect.s_nreloc <= 0)
- return 0;
-
- nreloc = tsect.s_nreloc;
-
- ldrseek(ldptr,1);
- while (nreloc-- > 0) {
- if (FREAD((char *)&crel, sizeof(crel),1,ldptr) != 1)
- return -1;
-
- pos = crel.r_vaddr;
- gette(outf, pos, &tstr);
- if (crel.r_type == R_ABS)
- tstr.t_reloc = R_NONE;
- else
- tstr.t_reloc = R_LONG; /* what about PC-relative? */
- tstr.t_isrel = 1;
- putte(outf, pos, &tstr);
- if (tstr.t_reloc == R_LONG) {
- gette(outf, pos+2, &tstr);
- tstr.t_isrel = 1;
- putte(outf, pos+2, &tstr);
- }
- }
-
- /*
- * Dont bother with data relocation at this stage. We'll
- * tie that up later.
- */
-
- return 1;
- }
-
- /*
- * Process a symbol in library file. The extern variable trelpos gives
- * the place in the main file where the library module is relocated.
- * We don't know the data position until we do the final merge, perhaps
- * not even then.
- */
- /* trelpos ??? */
-
- symbol dolsymb(sy, type, val, fid)
- register symbol sy;
- int type;
- long val;
- ef_fid fid;
- {
- t_entry tstr;
-
- switch (type) {
- default:
- return NULL;
-
- case S_EXT|S_UNDF:
- if (!sy->s_newsym)
- return sy;
- sy->s_value = val;
- if (val != 0) {
- sy->s_type = S_COMM;
- addit(&dreltab, sy);
- }
- else
- sy->s_type = S_UNDF;
- sy->s_glob = 1;
- break;
-
- case S_EXT|S_ABS:
- if (!sy->s_newsym) {
- if (sy->s_type != S_ABS || sy->s_value != val)
- lclash("abs");
- }
- sy->s_type = S_ABS;
- sy->s_value = val;
- sy->s_glob = 1;
- addit(&abstab, sy);
- break;
-
- case S_EXT|S_TEXT:
- sy->s_type = S_TEXT;
- val += trelpos - fid->ef_tbase;
- if (!sy->s_newsym) {
- if (val != sy->s_value)
- lclash("tsym");
- return sy;
- }
- sy->s_value = val;
- gette(&mainfile, val, &tstr);
- tstr.t_bdest = 1;
- tstr.t_gbdest = 1;
- sy->s_glob = 1;
- sy->s_link = tstr.t_lab;
- tstr.t_lab = sy;
- putte(&mainfile, val, &tstr);
- break;
-
- case S_EXT|S_BSS:
- if (!sy->s_newsym)
- return sy;
- sy->s_type = S_BSS;
- sy->s_value = val - fid->ef_bbase;
- goto datrest;
-
- case S_EXT|S_DATA:
- if (!sy->s_newsym)
- return sy;
- sy->s_type = S_DATA;
- sy->s_value = val - fid->ef_dbase;
- datrest:
- sy->s_glob = 1;
- addit(&dreltab, sy);
- break;
- }
-
- sy->s_newsym = 0;
- return sy;
- }
-
- /*
- * Change definition of undefined symbol as we define it.
- */
-
- void reassign(sy, val)
- register symbol sy;
- long val;
- {
- sy->s_value = val;
-
- if (val < mainfile.ef_tbase) {
- sy->s_type = S_ABS;
- addit(&abstab, sy);
- }
- else if (val < mainfile.ef_dbase) {
- t_entry tstr;
-
- sy->s_type = S_TEXT;
- gette(&mainfile, val, &tstr);
- tstr.t_bdest = 1;
- tstr.t_gbdest = 1;
- sy->s_glob = 1;
- sy->s_link = tstr.t_lab;
- tstr.t_lab = sy;
- putte(&mainfile, val, &tstr);
- }
- else {
- d_entry dstr;
-
- sy->s_type = val < mainfile.ef_bbase? S_DATA: S_BSS;
- getde(&mainfile, val, &dstr);
- sy->s_link = dstr.d_lab;
- dstr.d_lab = sy;
- putde(&mainfile, val, &dstr);
- }
- }
-
- /*
- * When we discover where bss or data come, reallocate the table.
- */
-
- void zapdat(seg, inc)
- int seg;
- long inc;
- {
- register int i;
- register symbol csymb;
- d_entry dent;
-
- for (i = 0; i < dreltab.c_int; i++) {
- csymb = dreltab.c_symb[i];
- if (csymb->s_type != seg)
- continue;
- csymb->s_value += inc;
- getde(&mainfile, csymb->s_value, &dent);
- csymb->s_link = dent.d_lab;
- dent.d_lab = csymb;
- putde(&mainfile, csymb->s_value, &dent);
- }
- }
-
- /*
- * Process relocation stuff in library module which we are inserting.
- * Horrors if something goes wrong.
- */
- /* trelpos, drelpos ??? */
-
- rrell2(ldptr, ldptr2, outf)
- LDFILE *ldptr,*ldptr2; /* a.out file (possibly in library) */
- ef_fid outf; /* Output file descriptor */
- {
- struct reloc crel;
- t_entry mtstr;
- d_entry mdstr;
- struct scnhdr tsect,dsect;
- struct syment isym;
- int nreloc;
- unsigned rtype;
- register long size;
- register symbol csymb;
- long pos, mpos, mval, lval;
- int dhere = 0; /* Mark whether bss done */
-
- ldshread(ldptr,1,&tsect);
- ldshread(ldptr,2,&dsect);
- if (tsect.s_nreloc <= 0 && dsect.s_nreloc <= 0)
- return 0;
-
- nreloc = tsect.s_nreloc;
-
- ldrseek(ldptr,1);
- while (nreloc-- > 0) {
- if (FREAD((char *)&crel, sizeof(crel),1,ldptr) != 1)
- lclash("rd trel");
-
- pos = crel.r_vaddr;
- mpos = crel.r_vaddr + trelpos;
- gette(&mainfile, mpos, &mtstr);
- if (crel.r_type == R_ABS)
- rtype = R_NONE;
- else
- rtype = R_LONG; /* what about PC-relative? */
- ldtbread(ldptr2,crel.r_symndx,&isym);
- lval = gettw(outf, pos, (int)rtype);
- mval = gettw(&mainfile, mpos, (int)rtype);
-
- if ( isym.n_sclass != C_EXT ) {
- switch (convtosun(&isym)) {
- case S_TEXT:
- if (lval + trelpos - outf->ef_tbase != mval)
- lclash("Trel");
- continue;
- case S_DATA:
- if (donedrel) {
- if (lval + drelpos - outf->ef_dbase != mval)
- lclash("Drel");
- }
- else {
- donedrel++;
- drelpos = mval - lval + outf->ef_dbase;
- }
- continue;
- case S_BSS:
- if (donebrel) {
- if (lval + brelpos - outf->ef_bbase != mval)
- lclash("brel");
- }
- else {
- donebrel++;
- brelpos = mval - lval + outf->ef_bbase;
- }
- continue;
- }
- } else {
- if (crel.r_symndx >= outf->ef_stcnt)
- lclash("Bad sy no");
- csymb = outf->ef_stvec[symord[crel.r_symndx]];
- if (csymb == NULL)
- continue;
- switch (csymb->s_type) {
- case S_UNDF:
- reassign(csymb, mval - lval);
- break;
- case S_ABS:
- if (lval + csymb->s_value != mval)
- lclash("abs rel");
- break;
- case S_TEXT:
- if (lval + csymb->s_value != mval)
- lclash("text rel");
- break;
- case S_DATA:
- if (lval + csymb->s_value != mval)
- lclash("data rel");
- break;
- case S_BSS:
- if (lval + csymb->s_value != mval)
- lclash("bss rel");
- break;
- case S_COMM:
- reassign(csymb, mval - lval);
- break;
- }
- mtstr.t_relsymb = csymb;
- mtstr.t_reldisp = lval;
- }
- }
-
- /*
- * Relocate data and bss if possible.
- */
-
- if (donebrel) {
- zapdat(S_BSS, brelpos);
- dhere++;
- }
-
- if (!donedrel)
- return;
-
-
- zapdat(S_DATA, drelpos);
-
- /*
- * And now repeat all that for data relocations if possible
- */
-
- nreloc = tsect.s_nreloc;
-
- ldrseek(ldptr,2);
-
- while (nreloc-- > 0) {
- if (FREAD((char *)&crel, sizeof(crel),1,ldptr) != 1)
- lclash("Rd drel");
-
- if (crel.r_type == R_ABS)
- continue;
-
- pos = crel.r_vaddr;
- mpos = crel.r_vaddr + drelpos;
- getde(&mainfile, mpos, &mdstr);
- rtype = R_LONG; /* what about PC-relative? */
- ldtbread(ldptr2,crel.r_symndx,&isym);
-
- lval = getdw(outf, pos, (int)rtype);
- mval = getdw(&mainfile, mpos, (int)rtype);
- if ( isym.n_sclass != C_EXT ) {
- switch (convtosun(&isym)) {
- case S_TEXT:
- if (lval + trelpos - outf->ef_tbase != mval)
- lclash("Trel-d");
- continue;
- case S_DATA:
- if (lval + drelpos - outf->ef_dbase != mval)
- lclash("Drel-d");
- continue;
- case S_BSS:
- if (donebrel) {
- if (lval + brelpos - outf->ef_bbase != mval)
- lclash("brel");
- }
- else {
- donebrel++;
- brelpos = mval - lval + outf->ef_bbase;
- }
- continue;
- }
- } else {
- if (crel.r_symndx >= outf->ef_stcnt)
- lclash("Bad sy no");
- csymb = outf->ef_stvec[symord[crel.r_symndx]];
- if (csymb == NULL)
- continue;
- switch (csymb->s_type) {
- case S_UNDF:
- reassign(csymb, mval - lval);
- break;
- case S_ABS:
- if (lval + csymb->s_value != mval)
- lclash("abs rel");
- break;
- case S_TEXT:
- if (lval + csymb->s_value != mval)
- lclash("text rel");
- break;
- case S_DATA:
- if (lval + csymb->s_value != mval)
- lclash("data rel");
- break;
- case S_BSS:
- if (lval + csymb->s_value != mval)
- lclash("bss rel");
- break;
- case S_COMM:
- reassign(csymb, mval - lval);
- break;
- }
- mtstr.t_relsymb = csymb;
- mtstr.t_reldisp = lval;
- }
- }
-
- if (dhere || !donebrel)
- return;
-
- zapdat(S_BSS, brelpos);
- }
-